Skip to content

Comments

feat: interactive questions via Telegram inline keyboards#67

Open
salemsayed wants to merge 1 commit intoTinyAGI:mainfrom
salemsayed:feat/interactive-questions
Open

feat: interactive questions via Telegram inline keyboards#67
salemsayed wants to merge 1 commit intoTinyAGI:mainfrom
salemsayed:feat/interactive-questions

Conversation

@salemsayed
Copy link
Contributor

Summary

  • Implements a question bridge that forwards Claude's clarifying questions to Telegram as inline keyboard buttons, enabling bidirectional interactive conversations in non-interactive (-p) mode
  • When Claude needs user input, it outputs structured [QUESTION] tags instead of using the disabled AskUserQuestion tool. The queue processor detects these, forwards to Telegram, waits for the user's button tap, then continues the conversation via --resume
  • Supports single-select, multi-select (with toggle + Done), and free-text "Other" responses

How it works

User sends message → Claude responds with [QUESTION] tag
  → Queue processor writes to queue/questions/
  → Telegram client renders inline keyboard
  → User taps button → answer written to queue/answers/
  → Queue processor reads answer, continues with --resume <sessionId>
  → Loop repeats until Claude stops asking questions

Screenshot

Telegram inline keyboard

Files changed

File Change
src/lib/question-bridge.ts New — parseQuestions, emitQuestion, pollForAnswer, writeAnswer, QUESTION_PROMPT
src/lib/types.ts Added QuestionData, AnswerData, InvokeResult interfaces
src/lib/config.ts Added QUEUE_QUESTIONS, QUEUE_ANSWERS paths
src/lib/invoke.ts Returns InvokeResult, adds --disallowed-tools, --append-system-prompt, --output-format json, --resume support
src/queue-processor.ts Question detection loop after invokeAgent(), heartbeat TTL refresh
src/channels/telegram-client.ts Inline keyboard builder, callback_query handler, questions queue watcher, free-text mode, multi-select

Key design decisions

  • File-based IPC (not sockets) — matches tinyclaw's existing queue architecture
  • wx flag on answer writes prevents duplicate answers from double-taps
  • Session ID capture via --output-format json on first call, then --resume <sessionId> for continuations
  • Heartbeat files refresh pending message TTL during long question loops (prevents 10-min timeout)
  • Graceful degradation — if Claude doesn't use [QUESTION] tags, response flows through as normal text
  • Telegram-only — interactive mode only activates for the Telegram channel (which supports inline keyboards)

Test plan

  • Build compiles cleanly (npm run build:main)
  • Claude outputs [QUESTION] tags with the stronger system prompt
  • Inline keyboard renders in Telegram with tappable buttons
  • Button tap writes answer and continues conversation
  • Multi-turn question loops work (tested 4+ rounds)
  • "Other" button triggers free-text mode
  • Duplicate tap protection (wx flag)
  • Timeout fallback (5-min per question)
  • Multi-select toggle + Done

🤖 Generated with Claude Code

- Add question-bridge module for Claude's AskUserQuestion → Telegram inline
  keyboard flow with poll-based answer retrieval
- Add configurable timeout (max_response_time) to agent invocations with
  SIGTERM→SIGKILL escalation to prevent hung sessions
- Strip CLAUDECODE env var from spawned processes to avoid nested session errors
- Deliver partial text before [QUESTION] tags as separate messages
- Add heartbeat handler to refresh pending message TTL during long processing
- Add proactive/agent-initiated messaging via senderId for direct delivery
- Improve error handling with 4xx permanent error detection in telegram client

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

1 participant